package org.xmx0632.connector.handlers;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.xmx0632.connector.protocol.message.Message;
import org.xmx0632.connector.protocol.message.Response;
import org.xmx0632.connector.protocol.processor.MessageProcessor;
import org.xmx0632.connector.util.SpringContextHolder;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

/**
 * 处理拿到的Java Message Object,
 * 
 * 根据不同的消息类型(org.xmx0632.connector.protocol.message.DemoMessage),
 * 
 * 调用对应的处理类(org.xmx0632.connector.protocol.handler.DemoMessageHandler)
 * 
 * 
 */
@Component
@Sharable
public class MessageProcessHandler<O> extends SimpleChannelInboundHandler<Message> {

	private static final Logger LOG = LoggerFactory.getLogger(MessageProcessHandler.class);

	@Override
	public void channelRead0(ChannelHandlerContext ctx, Message msg) throws Exception {
		LOG.debug("read message from client:{}", msg.toString());

		O responseMessage = getResponseMessage(msg);
		LOG.debug("responseMessage:{}", responseMessage);

		if (closeConnection(responseMessage)) {
			Channel channel = ctx.channel();
			LOG.debug("close connection from:{}", channel.remoteAddress());
			channel.close();
			return;
		}

		if (needNoResponse(responseMessage)) {
			LOG.debug("no response need to send back.");
			return;
		}

		ctx.pipeline().write(responseMessage);
	}

	private boolean needNoResponse(O responseMessage) {
		return responseMessage == null || responseMessage.equals(Response.NO_RESPONSE);
	}

	private boolean closeConnection(O responseMessage) {
		return responseMessage == null;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private O getResponseMessage(Message msg) {
		// 根据message.name获取对应的messageHandler,处理并生成返回消息
		MessageProcessor messageHandler = SpringContextHolder.getMessageProcessor(msg);
		Object executeResult = messageHandler.execute(msg);
		if (executeResult == null) {
			return null;
		}
		return (O) executeResult;
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		Channel incoming = ctx.channel();
		LOG.error("Channel {} exception.", incoming.remoteAddress(), cause);
		// 当出现异常就关闭连接
		incoming.close();
	}
}
